#include <gtk/gtk.h>
#include <jni.h>
//#include <string.h>
#include "gtkwire_GTKWireApp.h"
#include "gtkwire_command.h"
#include "gtkwire_databank.h"
#include "gtkwire_signal.h"
#include "gtkwire_utils.h"

/* Passes java commend on for gtk+ handling */
static void sendCommand (JNIEnv *env, jstring widget_name, jstring command, jint data_type, gpointer data, gpointer data2);

/* Virtual machine */
static JavaVM *jvm = NULL;

/* gtk+, threads and lib init */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_gtkInitFromJava (JNIEnv *env, jobject obj, jobject gtkLock)
{
	/* Get virtual machine reference */
	(*env)->GetJavaVM (env, &jvm);

	/* Init lib */
	init_sig_receiver (env, obj);
	init_comm (env, obj);
	init_bank ();
	init_java_gtk_lock (env, obj, gtkLock);
	init_utils (env);
	init_tree_model (env);

	/* Init gtk+ and threads */
	int argc;
	char argv[0];
	argc = 0;
	gtk_init_from_java (argc, argv);
}

/* Window init and gtk loop start using glade file. */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_startApp (JNIEnv *env, jobject obj, jstring glade_file)
{
	const char* cglade = (*env)->GetStringUTFChars (env, glade_file, NULL);
	app_init (cglade);
}

/* Window init and gtk loop start using wibdow widget file. */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_startWindowApp (JNIEnv *env, jobject obj, jstring window_name)
{
	const char* wname = (*env)->GetStringUTFChars (env, window_name, NULL);
	app_init_from_window (wname);
}

/* gtk stop*/
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_stopApp(JNIEnv *env, jobject obj)
{
	app_shutdown ();
}

/* Object() == null */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_Object_2
(JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jobject data)
{
	sendCommand (env, widget_name, command, DATA_NULL, NULL, NULL);
}

/* String */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2
(JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jstring data)
{
	const char *data_str = (*env)->GetStringUTFChars (env, data, NULL);
	gpointer data_p = (gpointer) data_str;
	sendCommand (env, widget_name, command, DATA_STRING, data_p, NULL);
	//-- utf not released, might go into display, but is memory leak if not
}

/* String[]. String are passed on as GList */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2_3Ljava_lang_String_2
(JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jobjectArray data)
{
	jsize len = (*env)->GetArrayLength (env, data);
	jstring jstr;
	char *utf_str;
	int i;
	GList *glist = NULL;
	for ( i = 0; i < len; i++ )
	{
		jstr = (jstring)((*env)-> GetObjectArrayElement (env, data, i));
		utf_str = (char*)((*env)->GetStringUTFChars (env, jstr, NULL ));
		glist = g_list_append (glist, (gpointer) utf_str);
	}

	sendCommand (env, widget_name, command, DATA_STRING_ARRAY, glist, (gpointer)len);
	//-- Glist not released, might go into display, but is memory leak if not?
}

/* int */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2I
(JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jint data)
{
	gpointer cdata = &data;

	sendCommand (env, widget_name, command, DATA_INT, cdata, NULL);
}

/* double */
JNIEXPORT void JNICALL
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2D
  (JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jdouble data)
{
	gpointer cdata = &data;

	sendCommand (env, widget_name, command, DATA_DOUBLE, cdata, NULL);
}

/* int[] */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2_3I
(JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jintArray data)
{
	int *cints = (*env)->GetIntArrayElements (env, data, NULL);
	jsize len = (*env)->GetArrayLength (env, data);

	sendCommand (env, widget_name, command, DATA_INT_ARRAY, cints, &len);
}

/* double[] */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2_3D
  (JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jdoubleArray data)
{
	double *cdoubles = (*env)->GetDoubleArrayElements (env, data, NULL );
	jsize len = (*env)->GetArrayLength (env, data);

	sendCommand (env, widget_name, command, DATA_DOUBLE_ARRAY, cdoubles, &len);
}

/* float[] */
JNIEXPORT void JNICALL Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2_3F
  (JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jfloatArray data)
{
	float *cfloats = (*env)->GetFloatArrayElements (env, data, NULL );
	jsize len = (*env)->GetArrayLength (env, data);

	sendCommand (env, widget_name, command, DATA_DOUBLE_ARRAY, cfloats, &len);
}

/* boolean */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2Z
  (JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jboolean data)
{
	gboolean b;
	if (data) b = TRUE;
	else b = FALSE;

	sendCommand (env, widget_name, command, DATA_BOOLEAN, (gpointer)&b, NULL);
}

/* String[], int[] */ 
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_sendCommand__Ljava_lang_String_2Ljava_lang_String_2_3Ljava_lang_String_2_3I
  (JNIEnv *env, jobject thisObj, jstring widget_name, jstring command, jobjectArray dataStr, jintArray dataInt)
{
	/* String[] */
	jsize len = (*env)->GetArrayLength(env, dataStr);
	jstring jstr;
	char *utf_str;
	int i;
	GList *glist = NULL;

	for( i = 0; i < len; i++ )
	{
		jstr = (jstring)((*env)-> GetObjectArrayElement( env, dataStr, i));
		utf_str = (char*)((*env)->GetStringUTFChars(env, jstr, NULL ));
		glist = g_list_append( glist, (gpointer) utf_str );
	}

	/* int[] */
	int *cints = (*env)->GetIntArrayElements( env, dataInt, NULL );

	sendCommand (env, widget_name, command, DATA_INT_ARRAY, glist, cints);
}

/* gtk+ widget creation */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_createGTKObject
(JNIEnv *env, jobject obj, jstring type, jstring name, jint hash, jobjectArray dataStr)
{
	/* Message */
	jsize len = (*env)->GetArrayLength(env, dataStr);
	jstring jstr;
	char *utf_str;
	int i;
	GList *glist = NULL;

	for ( i = 0; i < len; i++ ) 
	{
		jstr = (jstring)((*env)-> GetObjectArrayElement (env, dataStr, i));
		utf_str = (char*)((*env)->GetStringUTFChars (env, jstr, NULL));
		glist = g_list_append (glist, (gpointer) utf_str);
	}

	/* Widget name and type */
	const char *type_c;
	const char *name_c;

	type_c = (*env)->GetStringUTFChars (env, type, NULL);
	name_c = (*env)->GetStringUTFChars (env, name, NULL);

	create_widget (type_c, name_c, hash, glist);

	//--- Release Srings?
}

/* Connects widget with wignal */
JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_connectGTKSignal
(JNIEnv *env, jobject obj, jstring name, jstring con_sig)
{
	const char *widget_name;
	const char *signal_name;

	widget_name = (*env)->GetStringUTFChars (env, name, NULL);
	signal_name = (*env)->GetStringUTFChars (env, con_sig, NULL);

	 connect_widget (widget_name, signal_name);
	//--- Release Srings, NO for signal name .
}

/* All commands go through this */
static void
sendCommand ( JNIEnv *env, jstring widget_name, jstring command, jint data_type, gpointer data, gpointer data2 )
{
	const char *widget_name_c;
	const char *command_c;

	widget_name_c = (*env)->GetStringUTFChars (env, widget_name, NULL);
	command_c = (*env)->GetStringUTFChars (env, command, NULL);

	do_gtkwire_command (widget_name_c, command_c, data_type, data, data2);
	//--- Release Srings?
}

JNIEXPORT void JNICALL
Java_gtkwire_GTKWireApp_createGObjectN
  (JNIEnv *env, jobject obj, jint type_id, jint id, jobjectArray dataStr) 

{
	/* Message */
	jsize len = (*env)->GetArrayLength(env, dataStr);
	jstring jstr;
	char *utf_str;
	int i;
	GList *glist = NULL;

	for ( i = 0; i < len; i++ ) 
	{
		jstr = (jstring)((*env)-> GetObjectArrayElement (env, dataStr, i));
		utf_str = (char*)((*env)->GetStringUTFChars (env, jstr, NULL));
		glist = g_list_append (glist, (gpointer) utf_str);
	}

	create_new_g_object (type_id, id, glist);
	//--- Release Srings?
}

JNIEXPORT void JNICALL 
Java_gtkwire_GTKWireApp_createGObjectND
  (JNIEnv *env, jobject obj, jint type_id, jint id, jdoubleArray data)
{
	double *cdoubles = (*env)->GetDoubleArrayElements (env, data, NULL );
	create_new_g_object (type_id, id, cdoubles);
}

JNIEXPORT void JNICALL Java_gtkwire_GTKWireApp_setGObjectPropertyN
  (JNIEnv *env, jobject obj, jint g_id, jstring property, jint property_type, jstring value)
{
	GType type = get_gtype (property_type);

	const char *p_str = (*env)->GetStringUTFChars (env, property, NULL);
	const char *v_str = (*env)->GetStringUTFChars (env, value, NULL);

	GValue gval = get_gvalue (type, v_str);

	GObject *gobj = get_g_object (g_id);
	g_object_set_property (gobj, p_str, &gval);

	(*env)->ReleaseStringUTFChars(env, property, p_str);
	(*env)->ReleaseStringUTFChars(env, value, v_str);
}
